package commonUtility;

import org.jdom.*;   
import org.jdom.input.SAXBuilder;
import org.jdom.output.*; 
import java.io.*; 
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

/**
 * Questa classe è utilizzata per la gestione del file gateway.xml.
 * Questo file rappresenta lo sto interno di ogni nodo gateway, ed continuamente aggiornato
 * dai Thread incaricati della tramissione del file, ad ogni pacchetto RTCP ricevtuo come ack.
 * Si tratta quindi di una risorsa condivisa, ed è quindi necessario un meccanismo che ne
 * mantenga l'atomicità; per questo motivo si utilizza un unico metodo synchronized.
 * Per la gestione del file XML deve essere importata nel progetto la libreria JDOM.
 * @author alex
 */

public class XmlHandler { 

	static NetworkInterfaceIP net = new NetworkInterfaceIP();
	private String pathXml = "./xml/gateway.xml";
	private String pathXmlCopy = "./xml/gatewayCopy.xml";
	@SuppressWarnings("unused")
	private String network;
	private double wc;
	/**
	 * @return the wc
	 */
	public double getWc() {
		return wc;
	}
	/**
	 * @param wc the wc to set
	 */
	public void setWc(double wc) {
		this.wc = wc;
	}
	private double wr;
	/**
	 * @return the wr
	 */
	public double getWr() {
		return wr;
	}
	/**
	 * @param wr the wr to set
	 */
	public void setWr(double wr) {
		this.wr = wr;
	}

	public XmlHandler(double WeightClients,double WeightRSSI,String network) {
		this.wc=WeightClients;
		this.wr=WeightRSSI;
		this.network = network;
	}
	/**
	 * Questo metodo è utilizzato per creare il file XML gateway.xml
	 * @param filePath
	 * @param networkInterface 
	 * @throws IOException 
	 */
	public static void makeXml(String nodeName, String filePath, String networkInterface) throws IOException{
		FileWriter writer = new FileWriter(filePath);     
		Document doc;
		try {
			Element rootElement = new Element("GATEWAY");        
			rootElement.setAttribute("IP",net.getInterfacesIp(networkInterface)); 
			doc = new Document(rootElement); 
			XMLOutputter out = new XMLOutputter();
			out.setFormat(Format.getPrettyFormat()); 
			out.output(doc, writer);//Scrivo il file!
			writer.close();	
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * @param command : A seconda del segnale dato in ingresso sara' effettuata una diversa azione.
	 * @param clientInfo : Vettore che contiene i dati del client per l'aggiornamento.
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public synchronized Vector<String> changeStatusClientXml(String command,Vector<String> clientInfo){
		try{
			SAXBuilder builder = new SAXBuilder();
			Document document = null;
			//Creo gli elementi del file XML
			Element client = new Element("CLIENT");
			Element source = new Element("SOURCE"); 
			Element time = new Element("TRANSMITTEDTIME"); 
			Element rssi = new Element("RSSI"); 
			Element lambda = new Element("LAMBDA"); 
			Element port = new Element("PORT"); 
			Element state = new Element("STATE");	
			try {
				document = builder.build(new File(pathXml));
			} catch (JDOMException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			} 		
			Element root = document.getRootElement(); 	
			List<Element> children = root.getChildren(); 
			Iterator<Element> iterator = children.iterator(); 
			try{       
				if(command.equals("copy")){
					int n;	
					FileReader	getGatewayXml = new FileReader(pathXml);
					FileWriter	writeGatewaxXmlCopy	 = new FileWriter(pathXmlCopy);
					while ((n=getGatewayXml.read()) !=-1){
						writeGatewaxXmlCopy.write((char)n);
					}
					getGatewayXml.close();
					writeGatewaxXmlCopy.close();			
				}//copy
				if(command.equals("update")){
			//	    root.setAttribute("IP",net.getInterfacesIp(network)); 
					if(clientInfo.get(6)!=null){//Aggiorno valore di lambda mi è stato passato RSSI.
						int new_rssi = Integer.parseInt(clientInfo.get(6));
						int coding_quality = Integer.parseInt(clientInfo.get(7));
						System.err.println("Calcolo Lambda con Clients weight = "+wc+" e Rssi weight = "+wr +" e Coding Quality: "+coding_quality);
						int new_lambda = (int) (wc*children.size()+wr*new_rssi+((coding_quality+1)*0.5));		
						boolean uguale = false;
						if (iterator.hasNext()){
							while(iterator.hasNext()){ 
								Element item = (Element)iterator.next(); 
								String mac = item.getAttributeValue("MAC");
								//Trovato il client ne aggiorno il valore lambda.
								if (mac.equals(clientInfo.get(0))){
									uguale = true;
									item.getChild("RSSI").setText(Integer.toString(new_rssi));
									item.getChild("LAMBDA").setText(Integer.toString(new_lambda));
									break;
								} 
							}
							if(!uguale){
								System.err.println("Esco dal While senza trovare corrispondenza ed aggiungo il nuovo!");
								client.setAttribute("MAC",clientInfo.get(0)); 
								rssi.setText(Integer.toString(new_rssi));
								lambda.setText(Integer.toString(new_lambda));
								state.setText("ACTIVABLE");  
								client.addContent(state);
								client.addContent(source); 
								client.addContent(time);
								client.addContent(port);
								client.addContent(rssi);
								client.addContent(lambda);
								root.addContent(client);
							}	
						}
						else {
							client.setAttribute("MAC",clientInfo.get(0)); 
							rssi.setText(Integer.toString(new_rssi));
							lambda.setText(Integer.toString(new_lambda));
							state.setText("ACTIVABLE");  
							client.addContent(state);
							client.addContent(source); 
							client.addContent(time);
							client.addContent(port);
							client.addContent(rssi);
							client.addContent(lambda);
							root.addContent(client);
						}

					}//Devo solo aggiornare non si tratta di aggiornamento del LAMBDA
					else{
						while(iterator.hasNext()){ 
							Element item = (Element)iterator.next(); 
							String mac = item.getAttributeValue("MAC");
							if (mac.equals(clientInfo.get(0))){
								if(clientInfo.get(2)!=null){
									time = item.getChild("TRANSMITTEDTIME"); 
									time.setText(clientInfo.get(2));
									port = item.getChild("PORT");
									port.setText(clientInfo.get(4));
								}
								item.getChild("SOURCE").setText(clientInfo.get(1)); 
								item.getChild("STATE").setText(clientInfo.get(5)); 
							}	

						}//else
					}	//update

				}	
				if(command.equals("delete")){

					//Confronto ogni figlio con quello che corrisponde al mac dato, e lo rimuovo.
					while(iterator.hasNext()){ 
						client = (Element)iterator.next(); 
						String mac = client.getAttributeValue("MAC");
						if (mac.equals(clientInfo.get(0))){
							children.remove(client);
							System.out.println("Rimosso "+clientInfo.get(0));
							break;
						}		
					} 		
				}	//delete end

				if(command.equals("activableList")){//Restituisce tutti i client activable in un vettore.
					Vector <String> clients = new Vector<String>();	
					while(iterator.hasNext()){ 
						Element item = (Element)iterator.next(); 
						String status = item.getChild("STATE").getTextNormalize();
						if (status.equals("ACTIVABLE")){
							String mac = item.getAttributeValue("MAC");
							clients.add(mac);
						}		
					}//esco dal while e ritorno in vettore
					return clients;		
				}
				if(command.equals("rssi")){//Restituisce tutti i client activable in un vettore.
					Vector <String> getrssi = new Vector<String>();	
					while(iterator.hasNext()){ 
						client = (Element)iterator.next(); 
						String mac = client.getAttributeValue("MAC");
						if (mac.equals(clientInfo.get(0))){
							String c_rssi =	client.getChild("RSSI").getText();
							getrssi.add(c_rssi);
							break;
						}	
					} 	
					return getrssi;		
				}

				XMLOutputter outputter = new XMLOutputter(); 
				outputter.setFormat(Format.getPrettyFormat()); 
				try {
					outputter.output(document, new FileOutputStream(pathXml));
					document = null;

				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} 

				return null;
			}
			catch(Exception e){
				System.out.println("[XmlHandler: Eccezione nell' UPDATE del file xml!!]");
				e.printStackTrace();	
			}
		}catch(Exception e){
			e.printStackTrace();				
		}
		
		return null;
	}  
}